package com.cy.pj.sys.service.impl;

import com.cy.pj.common.anno.RequiredLog;
import com.cy.pj.common.pojo.PageObject;
import com.cy.pj.sys.dao.SysRoleDao;
import com.cy.pj.sys.dao.SysUserDao;
import com.cy.pj.sys.dao.SysUserRoleDao;
import com.cy.pj.sys.pojo.SysUser;
import com.cy.pj.sys.pojo.SysUserDept;
import com.cy.pj.sys.service.SysUserService;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @author 张琪
 * @date 2020/11/17
 * @describe
 */
@Service
public class SysUserServiceImpl implements SysUserService {

    @Autowired
    private SysUserDao sysUserDao;

    @Autowired
    private SysRoleDao sysRoleDao;

    @Autowired
    private SysUserRoleDao sysUserRoleDao;

    /**
     * 手动实现分页设置
     */
    @Override
    @RequiredLog(operation = "分页查询用户信息")
    public PageObject findPageObjects(String username, Integer pageCurrent) {
//        1.参数判断
        if(pageCurrent == null || pageCurrent < 1)
            throw new IllegalArgumentException("当前页码值无效");

        int rows = sysUserDao.getRowCount(username);
        if(rows == 0)
            throw new IllegalArgumentException("找不到对应的对象");

        int pageSize = 15;
        int startIndex = (pageCurrent - 1)* pageSize;
        int pageCount = rows / pageSize;
        if(pageCount == 0 || rows % pageSize != 0)pageCount++;

        List<SysUserDept> list = sysUserDao.findPageObjects(username, startIndex, pageSize);
        PageObject pageObject = new PageObject(rows, list, pageSize, pageCurrent);
        pageObject.setPageCount(pageCount);

        return pageObject;
    }


    /**
     *
     * @RequiresPermissions(该注解表示的方法为一个切入点方法) 注解由shiro框架提供, 此注解描述的方法为切入点方法, 表示此方法在执行时, 需要进行授权
     * 也就是说, 如果用户拥有访问此方法的权限, 才可以访问该方法
     * @param id
     * @param valid
     * @return
     */
    @RequiresPermissions("sys:user:update") //注解中字符串为权限标识
    @Override
    @RequiredLog(operation = "禁用启用")    // 此注解描述的方法为切入点方法
    public int validById(Integer id, Integer valid) {
//        1. 参数校验
        if(id == null || id < 1)
            throw new IllegalArgumentException("参数不合法, id = " + id);
        if(valid == null || (valid !=1 && valid!=0))
            throw new IllegalArgumentException("参数不合法, valid = " + valid);
//        2. 修改用户状态, 这里的admin为用户信息(假数据)
        int rows = sysUserDao.validById(id, valid, "admin");
        if(rows == 0)
            throw new IllegalArgumentException("该记录不存在");
        return rows;
    }

    @Override
    /**
     * 使用 PageHelper 来完成分页设置,
     */
    @RequiredLog(operation = "分页查询用户信息")
    public PageObject findPageObjects1(String username, Integer pageCurrent) {
//        1. 参数校验
        if(pageCurrent == null || pageCurrent < 1)
            throw new IllegalArgumentException("页码值不合法");
//        2. 分页查询
        int pageSize = 15;
//        调用PageHelper类(数据层)中的方法, 实现分页设置
//        并启动数据层的拦截机制, 对SQL语句进行一定的处理
        /*优点: 使我们的代码变得更简单
        * 缺点: 可读性差, 而且耗时更久
         */
        Page<SysUserDept> page = PageHelper.startPage(pageCurrent, pageSize);
        List<SysUserDept> records = sysUserDao.findPageObjects1(username);
//        当查询之后, 才会给page对象里面的属性赋值, 否则就为初始值.
        if(page.getTotal() == 0)
            throw new IllegalArgumentException("查询的结果不存在, 请重新查询");
        return new PageObject((int)page.getTotal(), records, page.getPageSize(), pageSize, pageCurrent);
    }


    @Override
    @Transactional
    public int saveObject(SysUser sysUser, Integer[] roleIds) {
//        1. 参数校验
        if(sysUser == null)
            throw new IllegalArgumentException("传输的数据为空");
        if(StringUtils.isEmpty(sysUser.getUsername()))
            throw new IllegalArgumentException("用户名为空");
        if(StringUtils.isEmpty(sysUser.getPassword()))
            throw new IllegalArgumentException("密码为空");
        if(roleIds == null)
            throw new IllegalArgumentException("必须为客户分配角色");

//        2. 密码加密(本次采用md5盐值加密 --> 盐值可以保证密码更加安全)
//        加密太简单, 换一种方式
//        String hashPwd =
//                DigestUtils.md5DigestAsHex(sysUser.getPassword().getBytes());
//        使用shiro 进行盐值md5加密
        String salt = UUID.randomUUID().toString();
        SimpleHash sh = new SimpleHash("md5", sysUser.getPassword(), salt, 1);
        sysUser.setPassword(sh.toHex());
        sysUser.setSalt(salt);
//        3. 保存自身信息
        int rows = sysUserDao.insertObject(sysUser);
//        4. 保存关系数据
        sysUserRoleDao.insertObjects(sysUser.getId(), roleIds);
        return rows;
    }

    @Override
    public Map<String, Object> doFindById(Integer id) {
        SysUserDept user = sysUserDao.doFindById(id);
        List<Integer> roleIds = sysUserRoleDao.findRoleIdsByUserId(id);
        Map<String, Object> map = new HashMap<>();
        map.put("user", user);      // 这里的key不能随便写, 要与客户端的取值一致
        map.put("roleIds", roleIds);

        return map;
    }

    @Override
    public int updateObject(SysUser sysUser, Integer[] roleIds) {
        //        1. 参数校验
        if(sysUser == null)
            throw new IllegalArgumentException("传输的数据为空");
        if(StringUtils.isEmpty(sysUser.getUsername()))
            throw new IllegalArgumentException("用户名为空");
        if(roleIds == null)
            throw new IllegalArgumentException("必须为客户分配角色");
//        2. 跟新用户数据
        int rows = sysUserDao.updateObject(sysUser);
//        3. 删除关系数据
        int row = sysUserRoleDao.deleteObjectsByUserId(sysUser.getId());
//        4. 保存新的关系数据
        sysUserRoleDao.insertObjects(sysUser.getId(), roleIds);
        return rows;
    }

    @Override
    public int updatePassword(String password, String newPassword, String cfgPassword) {
//        1. 判断新密码与确认密码是否相同 //参数邮箱
        if(StringUtils.isEmpty(newPassword))
            throw new IllegalArgumentException("新密码不能为空");
        if(StringUtils.isEmpty(cfgPassword))
            throw new IllegalArgumentException("确认密码不能为空");
        if(!cfgPassword.equals(newPassword))
            throw new IllegalArgumentException("新密码与确认密码不一致");
        if(StringUtils.isEmpty(password))
            throw new IllegalArgumentException("原密码不能为空");

//        2. 确认旧密码是否正确
        SysUser user = (SysUser) SecurityUtils.getSubject().getPrincipal();
        SimpleHash sh = new SimpleHash("MD5", password, user.getSalt(), 1);
        System.out.println(user.getPassword());
        System.out.println(sh.toHex());
        if(!user.getPassword().equals(sh.toHex()))
            throw new IllegalArgumentException("原密码不正确");

//        3. 对原密码进行加密
        String salt = UUID.randomUUID().toString();
        sh = new SimpleHash("MD5", newPassword, salt, 1);

//        4. 加密后的密码进行存储
        int rows = sysUserDao.updatePassword(sh.toHex(), salt, user.getId());
        if(rows == 0)
            throw new IllegalArgumentException("更新失败");
        return rows;
    }
}
